/*
 *  $Id: DeckManager.cs 1146 2010-09-30 15:33:38Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008-2009 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;

using AgateLib.Geometry;
using AgateLib.InputLib;

using Ragima.DeckManager;

namespace Ragima {
    public class DeckManagerScene: OldScene {
        private const int CardX = 14;
        private const int CardY = 25;
        private const int CardXStep = 110;
        private const int CardYStep = 140;
        private const int CardYReserve = 610;

        public static CardType[] CardTypeOrder = { CardType.Creature, CardType.Land, CardType.Spell, CardType.Enchantment, CardType.PlayerAbility };
        public static int[] CardTypeReverse = { -1, 0, 1, 2, 3, -1, 4 };

        private CardDeck _deck;
        private bool _activeReserve;
        private bool[] _elementFilters;
        private bool[] _typeFilters;
        private List<Card> _cards;
        private Region[] _cardRegions;
        private List<Region> _filterRegions;
        private CardListRegion _cardList;
        private Region[] _buttons;

        public DeckManagerScene() : base() {
            _deck = Application.Config.Player1.Deck.Copy();
            _activeReserve = false;
            _elementFilters = new bool[ElementType.Count];
            _typeFilters = new bool[CardTypeOrder.Length];
            _cards = new List<Card>();
            _cardRegions = new Region[30];
            int i = 0;
            for (int y = 0; y < 4; y++) {
                for (int x = 0; x < 6; x++) {
                    _cardRegions[i] = new CardRegion(this, false, i, CardX + x * CardXStep, CardY + y * CardYStep);
                    i++;
                }
            }
            for (int x = 0; x < 6; x++) {
                _cardRegions[i] = new CardRegion(this, true, x, CardX + x * CardXStep, CardYReserve);
                i++;
            }
            _filterRegions = new List<Region>();
            foreach (ElementType element in ElementType.AllElements)
                _filterRegions.Add(new ElementFilterRegion(this, element));
            _filterRegions.Add(new AllFilterRegion(this, true));
            foreach (CardType cardType in CardTypeOrder)
                _filterRegions.Add(new TypeFilterRegion(this, cardType));
            _filterRegions.Add(new AllFilterRegion(this, false));
            _cardList = new CardListRegion(this);

            _buttons = new Region[3];
            _buttons[0] = new UI.ButtonNHPSprite(Data.DeckManager.Buttons.GetSprite("button_new"), new Point(718, 130), NewDeck);
            _buttons[1] = new UI.ButtonNHPSprite(Data.DeckManager.Buttons.GetSprite("button_load"), new Point(808, 130), NewDeck);
            _buttons[2] = new UI.ButtonNHPSprite(Data.DeckManager.Buttons.GetSprite("button_save"), new Point(900, 130), NewDeck);

            SetFilters(_elementFilters, true);
            SetFilters(_typeFilters, true);
            UpdateCards();
            UpdateRegions();
        }

        public override void InitializeScene() {
            base.InitializeScene();
            RegisterHotKey(KeyCode.N, NewDeck);
        }

        public CardDeck Deck { get { return _deck; } }
        public List<Card> Cards { get { return _cards; } }

        private static void SetFilters(bool[] filters, bool value) {
            for (int i = 0; i < filters.Length; i++)
                filters[i] = value;
        }
        private static bool IsAllFilters(bool[] filters) {
            return Array.TrueForAll(filters, delegate(bool value) { return value; });
        }

        public bool GetElementFilter(ElementType element) {
            return _elementFilters[element.Number];
        }

        public void SetElementFilter(ElementType element, bool multiselect) {
            if (!multiselect) SetFilters(_elementFilters, false);
            _elementFilters[element.Number] = !_elementFilters[element.Number];
            UpdateCards();
        }

        public bool GetElementFilterAll() {
            return IsAllFilters(_elementFilters);
        }

        public void SetElementFilterAll() {
            SetFilters(_elementFilters, true);
            UpdateCards();
        }

        public bool GetTypeFilter(int num) {
            return _typeFilters[num];
        }

        public void SetTypeFilter(int num, bool multiselect) {
            if (!multiselect) SetFilters(_typeFilters, false);
            _typeFilters[num] = !_typeFilters[num];
            UpdateCards();
        }

        public bool GetTypeFilterAll() {
            return IsAllFilters(_typeFilters);
        }

        public void SetTypeFilterAll() {
            SetFilters(_typeFilters, true);
            UpdateCards();
        }

        private void UpdateCards() {
            _cards.Clear();
            foreach (Card card in CardManager.GetCards()) {
                if (card.MaxCount > 0 && CardListPredicate(card)) {
                    _cards.Add(card);
                }
            }
            _cards.Sort(CardListComparison);
            _cardList.Reset();
        }

        private bool CardListPredicate(Card card) {
            if (!(GetElementFilter(card.Element) || GetElementFilter(card.AdditionalElement))) return false;
            int type = CardTypeReverse[(int) card.CardType];
            if (type == -1) return false;
            return _typeFilters[type];
        }

        private int CardListComparison(Card a, Card b) {
            int result = a.Weight.CompareTo(b.Weight);
            if (result == 0) result = a.GetSumMana().CompareTo(b.GetSumMana());
            return result;
        }

        protected override void UpdateRegions(List<Region> regions) {
            regions.AddRange(_cardRegions);
            regions.AddRange(_filterRegions);
            regions.Add(_cardList);
            regions.AddRange(_buttons);
        }

        public override void Draw() {
            Data.DeckManager.Background.Draw();
            DrawRegions();
            DrawHint();
        }

        public void NewDeck() {
            _deck = new CardDeck();
        }

        public void AddCard(Card card, int count) {
            if (card == null || count <= 0)
                return;
            if (_deck.IsFull(_activeReserve)) {
                // TODO: вывод ошибки о максимальном размере колоды
                return;
            }
            int cards = _deck.GetCountOf(card);
            if (cards >= card.MaxCount) {
                // TODO: вывод ошибки о максимальном числе карт
                return;
            }
            if (!card.Category.CanAddToDeck(card, _deck)) {
                // TODO: вывод ошибки о конфликте категорий карт
                return;
            }
            count = Math.Min(count, card.MaxCount - cards);
            for (int i = count; i > 0; i--)
                _deck.Add(card, _activeReserve);
            // TODO: проверка на превышение ценности колоды
            // for (int i = count; i > 0; i--)
            // _deck.Remove(card, _activeReserve);
        }

        public void RemoveCard(Card card, bool all) {
            if (all) {
                DeckItem item = _deck.Find(card, _activeReserve);
                if (item != null)
                    _deck.Remove(item, _activeReserve);
            } else
                _deck.Remove(card, _activeReserve);
        }
    }
}
